package com.cyru.statemachine.core.builder.impl;

import com.cyru.statemachine.core.Action;
import com.cyru.statemachine.core.Condition;
import com.cyru.statemachine.core.State;
import com.cyru.statemachine.core.Transition;
import com.cyru.statemachine.core.builder.From;
import com.cyru.statemachine.core.builder.On;
import com.cyru.statemachine.core.builder.To;
import com.cyru.statemachine.core.builder.TransitionBuilder;
import com.cyru.statemachine.core.builder.When;
import com.cyru.statemachine.core.impl.States;
import com.cyru.statemachine.core.impl.TransitionImpl;

import java.util.ArrayList;
import java.util.List;

/**
 * description:
 *
 * @author zhangxuchuan
 * date 2022/5/2
 */
public class TransitionBuilderImpl<S, E, C> implements TransitionBuilder<S, E, C>, When<S, E, C>, From<S, E, C>, To<S, E, C>, On<S, E, C> {

    private final States<S, E, C> states;

    private final List<State<S, E, C>> sources = new ArrayList<>();

    private State<S, E, C> target;

    private final List<Transition<S, E, C>> transitions = new ArrayList<>();

    public TransitionBuilderImpl(States<S, E, C> states) {
        this.states = states;
    }


    @Override
    public To<S, E, C> to(S target) {
        this.target = states.getStateOrDefault(target);
        return this;
    }

    @Override
    public When<S, E, C> when(Condition<C> condition) {
        this.transitions.forEach(trigger -> trigger.getTrigger().setCondition(condition));
        return this;
    }

    @Override
    public On<S, E, C> on(E event) {
        for (State<S, E, C> source : sources) {
            transitions.add(source.addTransition(target, event));
        }
        return this;
    }

    @Override
    public From<S, E, C> from(S... sources) {
        for (S source : sources) {
            this.sources.add(states.getStateOrDefault(source));
        }
        return this;
    }

    @Override
    public To<S, E, C> with(S s) {
        State<S, E, C> state = states.getStateOrDefault(s);
        this.target = state;
        this.sources.add(state);
        return this;
    }

    @Override
    public void then(Action<S, E, C> action) {
        for (Transition<S, E, C> transition : this.transitions) {
            transition.getTrigger().setAction(action);
        }
    }
}
